﻿using System;

namespace Bricks
{

    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="TKernel"></typeparam>
    public abstract class LazyFacadeBase<TKernel> : FacadeBase<Lazy<TKernel>>, ILazyFacade<TKernel>
    {

        /// <summary>
        /// 
        /// </summary>
        /// <param name="lazyKernel"></param>
        protected LazyFacadeBase(Lazy<TKernel> lazyKernel) :
            base(() => lazyKernel)
        {
            if (lazyKernel == null)
            {
                throw new ArgumentNullException("lazyKernel");
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="action"></param>
        public void Execute(Action<TKernel> action)
        {
            Execute(
                kernelAccessor =>
                {
                    action.Invoke(kernelAccessor.Invoke());
                });
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="action"></param>
        /// <returns></returns>
        public TResult Execute<TResult>(Func<TKernel, TResult> action)
        {
            return Execute<TResult>(
                kernelAccessor =>
                {
                    return action.Invoke(kernelAccessor.Invoke());
                });
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="action"></param>
        public void Execute(Action<Func<TKernel>> action)
        {
            Execute<bool>(
                kernelAccessor =>
                {
                    action.Invoke(kernelAccessor);

                    return true;
                });
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="action"></param>
        /// <returns></returns>
        public virtual TResult Execute<TResult>(Func<Func<TKernel>, TResult> action)
        {
            return Execute<TResult>(
                lazy =>
                {
                    return action.Invoke(() => lazy.Value);
                });
        }
    }
}
